إجابات هذا السؤال هي جهد مجتمعي. تحرير الإجابات الموجودة لتحسين هذه الوظيفة. لا يقبل حاليًا إجابات أو تفاعلات جديدة. كيف تفسر إغلاق JavaScript لشخص لديه معرفة بالمفاهيم التي تتكون منها (على سبيل المثال الوظائف والمتغيرات وما شابه ذلك) ، ولكن لا يفهم الإغلاق نفسه؟ لقد رأيت مثال المخطط الوارد في ويكيبيديا ، لكن للأسف لم يساعد.
2020-12-07 22:16:40
1 2 3 التالى الإغلاق هو إقران: وظيفة و إشارة إلى النطاق الخارجي لهذه الوظيفة (بيئة معجمية) البيئة المعجمية هي جزء من كل سياق تنفيذ (إطار مكدس) ، وهي خريطة بين المعرفات (مثل أسماء المتغيرات المحلية) والقيم. تحتفظ كل وظيفة في JavaScript بمرجع لبيئتها المعجمية الخارجية. يتم استخدام هذا المرجع لتكوين سياق التنفيذ الذي تم إنشاؤه عند استدعاء دالة. يمكّن هذا المرجع الكود داخل الوظيفة من "رؤية" المتغيرات المعلنة خارج الوظيفة ، بغض النظر عن متى وأين يتم استدعاء الوظيفة. إذا تم استدعاء دالة بواسطة دالة ، والتي تم استدعاؤها بدورها بواسطة دالة أخرى ، فسيتم إنشاء سلسلة من المراجع إلى البيئات المعجمية الخارجية. هذه السلسلة تسمى سلسلة النطاق. في الكود التالي ، يُشكِّل الداخلي إغلاقًا بالبيئة المعجمية لسياق التنفيذ الذي تم إنشاؤه عند استدعاء foo ، مع الإغلاق على السر المتغير: function foo () { const secret = Math.trunc (Math.random () * 100) وظيفة العودة الداخلية () { console.log (`الرقم السري هو $ {secret} .`) } } const f = foo () // "secret" لا يمكن الوصول إليها مباشرة من خارج "foo" f () // الطريقة الوحيدة لاسترداد `secret` هي استدعاء` f` بعبارة أخرى: في JavaScript ، تحمل الدوال إشارة إلى "مربع الحالة" الخاص ، والتي يمكن الوصول إليها فقط (وأي وظائف أخرى تم الإعلان عنها في نفس البيئة المعجمية). مربع الحالة هذا غير مرئي لمستدعي الوظيفة ، مما يوفر آلية ممتازة لإخفاء البيانات وتغليفها. وتذكر: يمكن تمرير الوظائف في JavaScript مثل المتغيرات (وظائف من الدرجة الأولى) ، مما يعني أنه يمكن تمرير أزواج الوظائف والحالة هذه حول برنامجك: على غرار الطريقة التي يمكنك بها تمرير مثيل لفئة في C ++. إذا لم يكن JavaScript يحتوي على عمليات إغلاق ، فسيتعين تمرير المزيد من الحالات بين الوظائف بشكل صريح ، مما يجعل قوائم المعلمات أطول وتضجيج الكود. لذلك ، إذا كنت تريد أن تتمتع الوظيفة دائمًا بإمكانية الوصول إلى جزء خاص من الدولة ، فيمكنك استخدام الإغلاق. ... وكثيرًا ما نريد ربط الحالة بوظيفة ما. على سبيل المثال ، في Java أو C ++ ، عند إضافة متغير مثيل خاص وطريقة إلى فئة ، فأنت تربط الحالة بالوظيفة. في لغة C ومعظم اللغات الشائعة الأخرى ، بعد إرجاع الدالة ، لم يعد من الممكن الوصول إلى جميع المتغيرات المحلية بسبب تدمير إطار المكدس. في JavaScript ، إذا قمت بتعريف دالة داخل دالة أخرى ، فيمكن أن تظل المتغيرات المحلية للدالة الخارجية قابلة للوصول بعد الرجوع منها. بهذه الطريقة ، في الكود أعلاه ، يظل secret متاحًا لكائن الوظيفة الداخلي ، بعد إرجاعه من foo. استخدامات الإغلاق تكون عمليات الإغلاق مفيدة عندما تحتاج إلى حالة خاصة مرتبطة بوظيفة ما. هذا سيناريو شائع جدًا - وتذكر: لم يكن لدى JavaScript بنية فئة حتى عام 2015 ، وما زالت لا تحتوي على صيغة حقل خاص. الإغلاق يلبي هذه الحاجة. متغيرات المثيل الخاص في الكود التالي ، تغلق الوظيفة toString على تفاصيل السيارة. وظيفة السيارة (الشركة المصنعة ، الموديل ، السنة ، اللون) { إرجاع { إلى سلسلة() { إرجاع `$ {Manufacturer} $ {model} ($ {year}، $ {color})` } } } const car = سيارة جديدة ('Aston Martin'، 'V8 Vantage'، '2012'، 'Quantum Silver') console.log (car.toString ()) البرمجة الوظيفية في الكود التالي ، يتم إغلاق الوظيفة الداخلية على كل من fn و args. وظيفة كاري (fn) { args = [] عودة الدالة الداخلية (arg) { إذا كانت (args.length === fn.length) تُرجع fn (... args) args.push (arg) العودة الداخلية } } وظيفة إضافة (أ ، ب) { العودة أ + ب } curriedAdd = كاري (إضافة) console.log (curriedAdd (2) (3) ()) // 5 البرمجة الموجهة نحو الحدث في التعليمات البرمجية التالية ، تغلق الدالة onClick فوق المتغير BACKGROUND_COLOR. const $ = document.querySelector.bind (مستند) const BACKGROUND_COLOR = 'rgba (200،200،242،1)' وظيفة onClick () { $ ("body"). style.background = BACKGROUND_COLOR } $ ('button'). addEventListener (انقر فوق ، onClick) لاحظ بعض الأشياء هنا. في المثال أعلاه ، أستخدم سلوك إغلاق JavaScript. يسمح هذا السلوك لأي دالة بالوصول إلى النطاق الذي تم إنشاؤه فيه ، إلى أجل غير مسمى. لتطبيق هذا عمليًا ، استدعت فورًا دالة تُرجع دالة أخرى ، ولأن الوظيفة التي أعود لها حق الوصول إلى متغير العد الداخلي (بسبب سلوك الإغلاق الموضح أعلاه) ، ينتج عن ذلك نطاق خاص للاستخدام من خلال الناتج الناتج وظيفة ... ليست بهذه البساطة؟ دعونا نخففها ... إغلاق بسيط من سطر واحد // _______________________ تم الاستدعاء فورًا _______________________ // | | // | تم الاحتفاظ بالنطاق للاستخدام ___ تم إرجاعه كـ _____ | // | فقط عن طريق الوظيفة المرتجعة | قيمة الوظيفة | | // | | | | | | // v v v v v var func = (function () {var a = 'val'؛ return function () {alert (a)؛}؛}) () ؛ جميع المتغيرات خارج الدالة التي تم إرجاعها متاحة للدالة المرتجعة ، لكنها غير متاحة مباشرةً لكائن الوظيفة المرتجعة ... func () ؛ // التنبيهات "val" func.a ؛ // غير معرف احصل عليه؟ لذلك في مثالنا الأساسي ، يوجد متغير العد داخل الإغلاق ومتاح دائمًا لمعالج الأحداث ، لذلك يحتفظ بحالته من النقر للنقر. أيضًا ، يمكن الوصول إلى هذه الحالة المتغيرة الخاصة بشكل كامل ، لكل من القراءات والتعيين إلى المتغيرات الخاصة ذات النطاق. ها أنت ذا؛ أنت الآن تغلف هذا السلوك بالكامل. منشور مدونة كامل (بما في ذلك اعتبارات jQuery) | يصعب تفسير عمليات الإغلاق لأنها تُستخدم في جعل بعض السلوك يعمل بشكل يتوقعه الجميع بشكل حدسي على أي حال. أجد أن أفضل طريقة لشرحها (والطريقة التي تعلمت بها ما يفعلونه) هي تخيل الموقف بدونهم: const makePlus = الوظيفة (x) { دالة الإرجاع (y) {return x + y؛ } ؛ } const plus5 = makePlus (5) ؛ console.log (plus5 (3)) ؛ ماذا سيحدث هنا إذا لم يعرف JavaScript الإغلاق؟ فقط استبدل الاستدعاء في السطر الأخير بجسم طريقته (وهو أساسًا ما تفعله استدعاءات الوظائف) وستحصل على: console.log (x + 3) ؛ الآن ، أين تعريف x؟ لم نحدده في النطاق الحالي. الحل الوحيد هو السماح لـ plus5 بتنفيذ نطاقه (أو بالأحرى نطاق الشركة الأم). بهذه الطريقة ، يتم تعريف x جيدًا وهو مرتبط بالقيمة 5. | TLDR الإغلاق هو رابط بين الوظيفة وبيئتها المعجمية الخارجية (على سبيل المثال ، كما هو مكتوب) ، مثل أن تكون المعرفات (المتغيرات والمعلمات وإعلانات الوظائف وما إلى ذلك) المحددة داخل تلك البيئة مرئية من داخل الوظيفة ، بغض النظر عن متى أو حيث يتم استدعاء الوظيفة. تفاصيل في المصطلحات الخاصة بمواصفات ECMAScript ، يمكن القول بأنه تم تنفيذ الإغلاق بواسطة مرجع [[البيئة]] لكل كائن وظيفي ، والذي يشير إلى البيئة المعجمية التي يتم من خلالها تعريف الوظيفة. عندما يتم استدعاء دالة عبر طريقة [[Call]] الداخلية ، يتم نسخ مرجع [[بيئة]] على كائن الوظيفة إلى مرجع البيئة الخارجية لسجل البيئة لسياق التنفيذ المنشأ حديثًا (إطار المكدس). في المثال التالي ، تغلق الوظيفة f على البيئة المعجمية لسياق التنفيذ العام: الوظيفة و () {} في المثال التالي ، تغلق الوظيفة h على البيئة المعجمية للوظيفة g ، والتي بدورها تغلق على البيئة المعجمية لسياق التنفيذ العام. الوظيفة ز () { الوظيفة ح () {} } إذا تم إرجاع وظيفة داخلية بواسطة خارجي ، فستستمر البيئة المعجمية الخارجية بعد عودة الوظيفة الخارجية. هذا لأن البيئة المعجمية الخارجية يجب أن تكون متاحة إذا تم استدعاء الوظيفة الداخلية في النهاية. في المثال التالي ، تغلق الوظيفة j على البيئة المعجمية للدالة i ، مما يعني أن المتغير x مرئي من داخل الوظيفة j ، بعد فترة طويلة من انتهاء الوظيفة i من التنفيذ: الوظيفة الأول () { var x = 'mochacchino' وظيفة الإرجاع j () { console.log ("طباعة قيمة x ، من داخل الوظيفة j:" ، x) } } const ك = أنا () setTimeout (k ، 500) // استدعاء k (وهو j) بعد 500 مللي ثانية في الإغلاق ، المتغيرات في البيئة المعجمية الخارجية نفسها متوفرة ، وليست نسخًا. الوظيفة ل () { var y = 'Vanilla' ؛ إرجاع { setY: الوظيفة (القيمة) { ص = القيمة ؛ } ، logY: الوظيفة (القيمة) { console.log ('قيمة y هي:'، y) ؛ } } } كونست س = ل () o.logY () // قيمة y هي: الفانيليا o.setY ("شوكولاتة") o.logY () // قيمة y هي: chocolate تشكل سلسلة البيئات المعجمية ، المرتبطة بين سياقات التنفيذ عبر مراجع البيئة الخارجية ، سلسلة نطاق وتحدد المعرفات المرئية من أي وظيفة معينة. يرجى ملاحظة أنه في محاولة لتحسين الوضوح والدقة ،تم تغيير هذه الإجابة بشكل كبير من الأصل. | حسنًا ، مروحة الإغلاق البالغة من العمر 6 سنوات. هل تريد أن تسمع أبسط مثال على الإغلاق؟ لنتخيل الموقف التالي: سائق يجلس في سيارة. تلك السيارة داخل طائرة. الطائرة في المطار. قدرة السائق على الوصول إلى الأشياء خارج سيارته ، ولكن داخل الطائرة ، حتى لو غادرت تلك الطائرة المطار ، هو إغلاق. هذا هو. عندما تبلغ من العمر 27 عامًا ، انظر إلى الشرح الأكثر تفصيلاً أو إلى المثال أدناه. إليك كيف يمكنني تحويل قصة الطائرة الخاصة بي إلى الكود. var plane = function (defaultAirport) { var lastAirportLeft = defaultAirport ؛ فار سيارة = { سائق: { startAccessPlaneInfo: function () { setInterval (الوظيفة () { console.log ("آخر مطار كان" + lastAirportLeft) ؛ } ، 2000) ؛ } } } ؛ car.driver.startAccessPlaneInfo () ، إرجاع { LeaveTheAirport: function (airPortName) { lastAirportLeft = airPortName ، } } } ("مطار بوريسبيل الدولي") ؛ plane.leaveTheAirport ("John F. Kennedy")؛ | هذه محاولة لتوضيح العديد من حالات سوء الفهم (المحتملة) حول عمليات الإغلاق التي تظهر في بعض الإجابات الأخرى. لا يتم إنشاء الإغلاق فقط عند إرجاع دالة داخلية. في الواقع ، لا تحتاج وظيفة التضمين إلى العودة على الإطلاق من أجل إنشاء إغلاقها. يمكنك بدلاً من ذلك تعيين وظيفتك الداخلية إلى متغير في نطاق خارجي ، أو تمريرها كوسيطة لدالة أخرى حيث يمكن استدعاؤها على الفور أو في أي وقت لاحق. لذلك ، من المحتمل أن يتم إنشاء إغلاق وظيفة التضمين بمجرد استدعاء وظيفة التضمين نظرًا لأن أي وظيفة داخلية لها حق الوصول إلى هذا الإغلاق كلما تم استدعاء الوظيفة الداخلية ، قبل أو بعد إرجاع دالة التضمين. لا يشير الإغلاق إلى نسخة من القيم القديمة للمتغيرات في نطاقه. المتغيرات نفسها هي جزء من الإغلاق ، وبالتالي فإن القيمة التي تظهر عند الوصول إلى أحد هذه المتغيرات هي أحدث قيمة في وقت الوصول إليها. هذا هو السبب في أن الوظائف الداخلية التي يتم إنشاؤها داخل الحلقات يمكن أن تكون صعبة ، لأن كل واحدة لديها وصول إلى نفس المتغيرات الخارجية بدلاً من الحصول على نسخة من المتغيرات في وقت إنشاء الوظيفة أو استدعائها. تتضمن "المتغيرات" في الإغلاق أي وظائف مسماة معلنة داخل الوظيفة. وتشمل أيضًا حجج الوظيفة. يمكن للإغلاق أيضًا الوصول إلى متغيرات الإغلاق التي تحتوي عليها ، وصولاً إلى النطاق العالمي. تستخدم عمليات الإغلاق الذاكرة ، ولكنها لا تسبب تسربًا للذاكرة نظرًا لأن JavaScript بمفرده يقوم بتنظيف الهياكل الدائرية الخاصة به التي لم تتم الإشارة إليها. يتم إنشاء تسريبات ذاكرة Internet Explorer التي تتضمن عمليات إغلاق عندما يفشل في فصل قيم سمات DOM التي تشير إلى عمليات الإغلاق ، وبالتالي الحفاظ على المراجع إلى الهياكل الدائرية المحتملة. | لقد كتبت منشور مدونة منذ فترة تشرح فيه عمليات الإغلاق. إليك ما قلته عن عمليات الإغلاق من حيث سبب رغبتك في ذلك. عمليات الإغلاق هي وسيلة للسماح بوظيفة لها متغيرات خاصة مستمرة - وهذا هو ، المتغيرات التي واحدة فقط تعرف الوظيفة ، حيث يمكنها ذلك تتبع المعلومات من الأوقات السابقة أنه تم تشغيله. وبهذا المعنى ، فإنهم يسمحون لوظيفة ما بالتصرف إلى حد ما مثل كائن بسمات خاصة. المشاركة الكاملة: إذن ما هي أشياء الإغلاق هذه؟ | عمليات الإغلاق بسيطة: يغطي المثال البسيط التالي جميع النقاط الرئيسية لإغلاق JavaScript. * هنا مصنع ينتج آلات حاسبة يمكنها الجمع والمضاعفة: وظيفة make_calculator () { فار ن = 0 ؛ // هذه الآلة الحاسبة تخزن رقمًا واحدًا n إرجاع { add: الوظيفة (أ) { ن + = أ ؛ عودة ن ؛ } ، ضرب: الوظيفة (أ) { ن * = أ ؛ عودة ن ؛ } } ؛ } first_calculator = make_calculator () ، second_calculator = make_calculator () ، first_calculator.add (3) ، // إرجاع 3 second_calculator.add (400) ، // يُرجع 400 first_calculator.multiply (11) ، // يُرجع 33 second_calculator.multiply (10) ، // تُرجع 4000 النقطة الأساسية: كل استدعاء لـ make_calculator يُنشئ متغيرًا محليًا جديدًا n ، والذي يظل قابلاً للاستخدام من خلال وظائف الإضافة والمضاعفة الخاصة بهذه الآلة الحاسبة لفترة طويلة بعد عودة make_calculator. إذا كنت معتادًا على إطارات المكدس ، فإن هذه الآلات الحاسبة تبدو غريبة: كيف يمكنهم الاستمرار في الوصول إلى n بعد إرجاع make_calculator؟ الجواب هو تخيل أن JavaScript لا تستخدم "إطارات مكدسة" ، ولكنها تستخدم بدلاً من ذلك "إطارات كومة" ، والتي يمكن أن تستمر بعد استدعاء الوظيفة الذي يجعلها تعود. الدوال الداخلية مثل الجمع والضرب ، والتي تسمى متغيرات الوصول المعلنة في دالة خارجية ** ، تسمى عمليات الإغلاق. هذا إلى حد كبير كل ما في الإغلاق. * على سبيل المثال ، يغطي جميع النقاط الواردة في مقالة "Closures for Dummies" الواردة في إجابة أخرى ، باستثناء المثال 6 ، الذي يوضح ببساطة أنه يمكن استخدام المتغيرات قبل الإعلان عنها ، وهي حقيقة لطيفة يجب معرفتها ولكنها غير مرتبطة تمامًا بالإغلاق. يغطي أيضًا جميع النقاط في الإجابة المقبولة ، باستثناء النقاط (1) التي تنسخ الدالات وسيطاتها إلى متغيرات محلية (وسيطات الوظيفة المسماة) ، و (2) نسخ الأرقامينشئ رقمًا جديدًا ، لكن نسخ مرجع كائن يمنحك مرجعًا آخر لنفس الكائن. من الجيد معرفة هذه أيضًا ولكنها مرة أخرى غير مرتبطة تمامًا بعمليات الإغلاق. إنه أيضًا مشابه جدًا للمثال في هذه الإجابة ولكنه أقصر قليلاً وأقل تجريدًا. إنه لا يغطي الهدف من هذه الإجابة أو هذا التعليق ، وهو أن JavaScript يجعل من الصعب توصيل القيمة الحالية لمتغير حلقة في وظيفتك الداخلية: لا يمكن إجراء خطوة "التوصيل" إلا باستخدام وظيفة مساعدة تتضمن وظيفتك الداخلية ويتم استدعاؤها في كل حلقة تكرار. (بالمعنى الدقيق للكلمة ، تصل الوظيفة الداخلية إلى نسخة المتغير لوظيفة المساعد ، بدلاً من توصيل أي شيء.) مرة أخرى ، مفيدة جدًا عند إنشاء الإغلاق ، ولكنها ليست جزءًا من ماهية الإغلاق أو كيفية عمله. هناك ارتباك إضافي بسبب عمليات الإغلاق التي تعمل بشكل مختلف في اللغات الوظيفية مثل ML ، حيث ترتبط المتغيرات بالقيم بدلاً من مساحة التخزين ، مما يوفر تدفقًا ثابتًا من الأشخاص الذين يفهمون الإغلاق بطريقة (أي طريقة "التوصيل") أي ببساطة غير صحيح لجافا سكريبت ، حيث ترتبط المتغيرات دائمًا بمساحة التخزين وليس بالقيم أبدًا. ** أي دالة خارجية ، إذا كانت عدة متداخلة ، أو حتى في السياق العام ، كما تشير هذه الإجابة بوضوح. | كيف أشرح ذلك لطفل في السادسة من عمره: أنت تعرف كيف يمكن للكبار امتلاك منزل ، ويطلقون عليه اسم المنزل؟ عندما يكون لدى الأم طفل ، فإن الطفل لا يمتلك أي شيء حقًا ، أليس كذلك؟ لكن والديها يمتلكان منزلاً ، لذلك عندما يسأل أحدهم الطفل "أين منزلك؟" ، يمكنه الإجابة "هذا المنزل!" ، ويشير إلى منزل والديها. "الإغلاق" هو قدرة الطفل دائمًا (حتى لو كان في الخارج) على القول بأن لديه منزلًا ، على الرغم من أن الوالد هو من يمتلك المنزل. | هل يمكنك شرح عمليات الإغلاق لطفل يبلغ من العمر 5 سنوات؟ * ما زلت أعتقد أن تفسير Google يعمل جيدًا وموجزًا: / * * عندما يتم تعريف وظيفة في وظيفة أخرى وهي * لديه حق الوصول إلى سياق الوظيفة الخارجية حتى بعد * ترجع الدالة الخارجية. * * مفهوم مهم للتعلم في JavaScript. * / الوظيفة الخارجية الوظيفة (بعض الأرقام) { var someString = 'Hey!'؛ var content = document.getElementById ('content') ؛ الوظيفة innerFunction () { content.innerHTML = someNum + ':' + someString؛ المحتوى = لا شيء ؛ // تسرب ذاكرة Internet Explorer لمرجع DOM } الوظيفة الداخلية () ؛ } الوظيفة الخارجية (1) ؛ * سؤال C # | أميل إلى التعلم بشكل أفضل من خلال المقارنات الجيدة / السيئة. أحب أن أرى رمز العمل متبوعًا برمز غير عامل من المحتمل أن يواجهه شخص ما. لقد قمت بتجميع jsFiddle الذي يقوم بإجراء مقارنة ويحاول تلخيص الاختلافات في أبسط التفسيرات التي يمكنني التوصل إليها. تم الإغلاق بشكل صحيح: console.log ("الإغلاق الحق") ؛ var arr = [] ؛ وظيفة createClosure (n) { وظيفة الإرجاع () { العودة 'n =' + n ؛ } } لـ (var index = 0 ؛ index <10 ؛ index ++) { arr [index] = createClosure (index) ؛ } لـ (var index in arr) { console.log (arr [index] ()) ؛ } في الكود أعلاه ، يتم استدعاء createClosure (n) في كل تكرار للحلقة. لاحظ أنني قمت بتسمية المتغير n لإبراز أنه متغير جديد تم إنشاؤه في نطاق دالة جديد وليس نفس المتغير مثل الفهرس المرتبط بالنطاق الخارجي. هذا يخلق نطاقًا جديدًا و n مرتبط بهذا النطاق ؛ هذا يعني أن لدينا 10 نطاقات منفصلة ، واحد لكل تكرار. تُعيد createClosure (n) دالة تُرجع n ضمن هذا النطاق. داخل كل نطاق ، يرتبط n بأي قيمة كانت لديه عند استدعاء createClosure (n) لذا فإن الوظيفة المتداخلة التي يتم إرجاعها ستعيد دائمًا قيمة n التي كانت لديها عند استدعاء createClosure (n). تم الإغلاق بشكل خاطئ: console.log ("الإغلاق خطأ") ؛ دالة createClosureArray () { var badArr = [] ؛ لـ (var index = 0 ؛ index <10 ؛ index ++) { badArr [index] = function () { إرجاع 'n =' + index ؛ } ؛ } عودة سيئة } var badArr = createClosureArray () ، لـ (var index in badArr) { console.log (badArr [index] ()) ، } في الكود أعلاه ، تم نقل الحلقة داخل وظيفة createClosureArray () وتعيد الوظيفة الآن فقط المصفوفة المكتملة ، والتي تبدو للوهلة الأولى أكثر سهولة. ما قد لا يكون واضحًا هو أنه نظرًا لأنه يتم استدعاء createClosureArray () بمجرد إنشاء نطاق واحد فقط لهذه الوظيفة بدلاً من واحد لكل تكرار للحلقة. ضمن هذه الوظيفة يتم تحديد متغير يسمى index. تعمل الحلقة وتضيف وظائف إلى الصفيف الذي يُرجع الفهرس. لاحظ أن الفهرس يتم تعريفه ضمن وظيفة createClosureArray التي يتم استدعاؤها مرة واحدة فقط. نظرًا لوجود نطاق واحد فقط داخل دالة createClosureArray () ، فإن الفهرس مرتبط فقط بقيمة داخل هذا النطاق. بمعنى آخر ، في كل مرة تغير الحلقة قيمة الفهرس ، فإنها تغيرها لكل ما يشير إليها ضمن هذا النطاق. جميع الوظائف المضافة إلى المصفوفة ترجع متغير الفهرس SAME من النطاق الأصلي حيث تم تعريفهبدلاً من 10 نطاقات مختلفة من 10 نطاقات مختلفة مثل المثال الأول. والنتيجة النهائية هي أن جميع الوظائف العشر ترجع نفس المتغير من نفس النطاق. بعد انتهاء الحلقة وتم تعديل الفهرس ، كانت القيمة النهائية 10 ، وبالتالي فإن كل دالة مضافة إلى المصفوفة ترجع قيمة متغير الفهرس الفردي الذي تم تعيينه الآن على 10. نتيجة تم الإغلاق بشكل صحيح ن = 0 ن = 1 ن = 2 ن = 3 ن = 4 ن = 5 ن = 6 ن = 7 ن = 8 ن = 9 تم الإغلاق بشكل خاطئ ن = 10 ن = 10 ن = 10 ن = 10 ن = 10 ن = 10 ن = 10 ن = 10 ن = 10 ن = 10 | ويكيبيديا عن الإغلاق: في علوم الكمبيوتر ، يعتبر الإغلاق وظيفة مع بيئة مرجعية للأسماء غير المحلية (المتغيرات الحرة) لتلك الوظيفة. من الناحية الفنية ، في JavaScript ، كل وظيفة هي إغلاق. لديه دائمًا إمكانية الوصول إلى المتغيرات المحددة في النطاق المحيط. نظرًا لأن إنشاء النطاق المحدد في JavaScript هو وظيفة ، وليس كتلة تعليمات برمجية كما هو الحال في العديد من اللغات الأخرى ، فإن ما نعنيه عادةً بالإغلاق في JavaScript هو وظيفة تعمل مع المتغيرات غير المحلية المحددة في الوظيفة المحيطة المنفذة بالفعل. غالبًا ما تُستخدم عمليات الإغلاق لإنشاء وظائف مع بعض البيانات الخاصة المخفية (ولكن هذا ليس هو الحال دائمًا). فار ديسيبل = (وظيفة () { // إنشاء كائن مخفي ، والذي سيحتفظ بالبيانات // لا يمكن الوصول إليه من الخارج. var data = {} ؛ // أنشئ وظيفة ، والتي ستوفر بعض الوصول إلى البيانات. وظيفة العودة (مفتاح ، val) { إذا (val === undefined) {إرجاع البيانات [مفتاح]} // Get آخر {إرجاع البيانات [مفتاح] = val} // مجموعة } // نحن ندعو الوظيفة المحيطة المجهولة ، // إعادة الوظيفة الداخلية أعلاه ، وهي عبارة عن إغلاق. }) () ؛ db ('x') // -> undefined db ('x'، 1) // تعيين x على 1 ديسيبل ('س') // -> 1 // من المستحيل الوصول إلى كائن البيانات نفسه. // نحن قادرون على الحصول عليه أو تعيينه بشكل فردي. EMS المثال أعلاه يستخدم دالة مجهولة تم تنفيذها مرة واحدة. ولكن لا يجب أن تكون. يمكن تسميتها (مثل mkdb) وتنفيذها لاحقًا ، مما يؤدي إلى إنشاء وظيفة قاعدة بيانات في كل مرة يتم استدعاؤها. سيكون لكل دالة تم إنشاؤها كائن قاعدة بيانات مخفي خاص بها. مثال آخر على استخدام الإغلاق هو عندما لا نعيد دالة ، ولكن كائنًا يحتوي على وظائف متعددة لأغراض مختلفة ، كل من هذه الوظائف لها حق الوصول إلى نفس البيانات. | قمت بتجميع برنامج تعليمي تفاعلي لـ JavaScript لشرح كيفية عمل الإغلاق. ما هو الإغلاق؟ إليك أحد الأمثلة: var create = function (x) { var f = function () { عودة س ؛ // يمكننا الرجوع إلى x هنا! } ؛ العودة و ؛ } ؛ // 'create' تأخذ حجة واحدة ، تنشئ دالة var g = create (42) ؛ // g هي وظيفة لا تأخذ أي وسيطات الآن فار ص = ز () ؛ // y هو 42 هنا | سيتذكر الأطفال دائمًا الأسرار التي شاركوها مع والديهم ، حتى بعد والديهم ذهب. هذا هو ما هي الإغلاق للوظائف. أسرار وظائف JavaScript هي المتغيرات الخاصة var parent = function () { var name = "Mary" ؛ // سر } في كل مرة تسميها ، يتم إنشاء المتغير المحلي "name" وإعطائه اسم "Mary". وفي كل مرة تخرج فيها الوظيفة ، يضيع المتغير ويُنسى الاسم. كما قد تتخيل ، نظرًا لأنه يتم إعادة إنشاء المتغيرات في كل مرة يتم استدعاء الوظيفة ، ولن يعرفها أي شخص آخر ، يجب أن يكون هناك مكان سري يتم تخزينها فيه. يمكن أن يطلق عليه غرفة الأسرار أو المكدس أو النطاق المحلي ولكن هذا لا يهم حقًا. نحن نعلم أنهم موجودون هناك ، في مكان ما ، مختبئون في الذاكرة. ولكن ، في JavaScript ، يوجد هذا الشيء الخاص جدًا الذي يتم إنشاؤه داخل وظائف أخرى ، ويمكن أيضًا معرفة المتغيرات المحلية لوالديهم والاحتفاظ بها طوال حياتهم. var parent = function () { var name = "Mary" ؛ var child = function (childName) { // يمكنني أيضًا رؤية أن "الاسم" هو "ماري" } } لذلك ، طالما أننا في وظيفة الوالدين ، فيمكنها إنشاء وظيفة فرعية واحدة أو أكثر تشارك المتغيرات السرية من المكان السري. لكن الشيء المحزن هو أنه إذا كان الطفل أيضًا متغيرًا خاصًا لوظيفته الأم ، فإنه سيموت أيضًا عندما ينتهي الوالد ، وتموت الأسرار معهم. لكي يعيش الطفل ، يجب أن يغادر قبل فوات الأوان var parent = function () { var name = "Mary" ؛ var child = function (childName) { إرجاع "My name is" + childName + "، تابع لـ" + name ؛ } عودة الطفل // يترك الطفل الوالد -> } var child = الوالد () ؛ // <- وهنا في الخارج والآن ، على الرغم من أن ماري "لم تعد تعمل" ، لم تضيع ذكراها وسيتذكر طفلها دائمًا اسمها والأسرار الأخرى التي شاركوها أثناء وقتهم معًا. لذا ، إذا سميت الطفلة "أليس" ، فسوف تستجيب child ("Alice") => "اسمي أليس ، ابنة مريم" هذا كل ما يمكن قوله. | لا أفهم سبب تعقيد الإجابات هنا. هنا إغلاق: فار أ = 42 ؛ الوظيفة ب () {إرجاع أ ؛ } نعم. ربما تستخدم هذا مرات عديدة في اليوم. لا يوجد سبب للاعتقاد بأن عمليات الإغلاق هي اختراق تصميم معقد يجب معالجتهمشاكل محددة. لا ، الإغلاق يتعلق فقط باستخدام متغير يأتي من نطاق أعلى من منظور المكان الذي تم فيه إعلان الوظيفة (لا يتم تشغيلها). الآن ما يتيح لك القيام به يمكن أن يكون أكثر إثارة ، انظر الإجابات الأخرى. | مثال للنقطة الأولى بواسطة dlaliberte: لا يتم إنشاء الإغلاق فقط عند إرجاع دالة داخلية. في الواقع ، لا تحتاج وظيفة التضمين إلى العودة على الإطلاق. يمكنك بدلاً من ذلك تعيين وظيفتك الداخلية إلى متغير في نطاق خارجي ، أو تمريرها كوسيطة لدالة أخرى حيث يمكن استخدامها على الفور. لذلك ، من المحتمل أن يكون إغلاق وظيفة التضمين موجودًا بالفعل في وقت استدعاء وظيفة التضمين نظرًا لأن أي وظيفة داخلية لها حق الوصول إليها بمجرد استدعائها. فار أنا ؛ وظيفة foo (x) { فار tmp = 3 ؛ أنا = الوظيفة (ص) { console.log (x + y + (++ tmp)) ؛ } } فو (2) ، ط (3) ؛ | الإغلاق هو المكان الذي تستطيع فيه الوظيفة الداخلية الوصول إلى المتغيرات في وظيفتها الخارجية. ربما يكون هذا هو أبسط تفسير من سطر واحد يمكنك الحصول عليه للإغلاق. | أعلم أن هناك الكثير من الحلول بالفعل ، لكنني أعتقد أن هذا النص الصغير والبسيط يمكن أن يكون مفيدًا لتوضيح المفهوم: // سيعيد makeSequencer وظيفة "Sequencer" var makeSequencer = function () { var _count = 0 ؛ // لا يمكن الوصول إليها خارج هذه الوظيفة var Sequencer = function () { إرجاع _count ++ ؛ } منظم العودة } var fnext = makeSequencer () ، var v0 = fnext () ؛ // v0 = 0 ؛ var v1 = fnext () ؛ // v1 = 1 ؛ var vz = fnext._count // vz = غير محدد | أنت تنام وتدعو دان. أخبر دان أن يحضر وحدة تحكم XBox واحدة. دعا دان بولس. يطلب دان من بول إحضار وحدة تحكم واحدة. كم عدد المتحكمين الذين تم إحضارهم للحزب؟ function sleepOver (howManyControllersToBring) { var numberOfDansControllers = howManyControllersToBring ؛ إرجاع دالة danInvitedPaul (numberOfPaulsControllers) { var totalControllers = numberOfDansControllers + numberOfPaulsControllers ؛ عودة مجموع المتحكمات ؛ } } var howManyControllersToBring = 1 ؛ var callingDan = sleepOver (howManyControllersToBring) ، // السبب الوحيد لدعوة بولس هو دعوة دان. // لذا حددنا دعوة بولس = دعوة دان. var danInvitedPaul = callingDan (howManyControllersToBring) ، تنبيه ("كانت هناك" + danInvitedPaul + "وحدات تحكم تم إحضارها إلى الحزب.") ؛ | أوضح مؤلف كتاب الإغلاق عمليات الإغلاق جيدًا ، موضحًا سبب حاجتنا إليها وشرح أيضًا البيئة المعجمية الضرورية لفهم عمليات الإغلاق. هذا هو الملخص: ماذا لو تم الوصول إلى متغير ولكنه ليس محليًا؟ مثلما هو الحال هنا: في هذه الحالة ، يجد المترجم المتغير في ملف كائن البيئة المعجمي الخارجي. تتكون العملية من خطوتين: أولاً ، عند إنشاء دالة f ، لا يتم إنشاؤها في ملف فارغ الفراغ. يوجد كائن LexicalEnvironment حالي. في القضية أعلاه ، إنها نافذة (لم يتم تحديدها في وقت الوظيفة خلق). عندما يتم إنشاء دالة ، فإنها تحصل على خاصية مخفية ، تسمى [[النطاق]] ، والتي تشير إلى بيئة LexicalEnvironment الحالية. إذا تمت قراءة متغير ، ولكن لا يمكن العثور عليه في أي مكان ، فسيتم إنشاء خطأ. وظائف متداخلة يمكن أن تتداخل الوظائف مع بعضها البعض ، وتشكل سلسلة من البيئات المعجمية والتي يمكن أن تسمى أيضًا سلسلة النطاق. إذن ، الوظيفة g لها حق الوصول إلى g و a و f. الإغلاق قد تستمر وظيفة متداخلة في العمل بعد انتهاء الوظيفة الخارجية: ترميز البيئات المعجمية: كما نرى ، فإن this.say هي خاصية في كائن المستخدم ، لذلك تستمر في العيش بعد اكتمال المستخدم. وإذا كنت تتذكر ، عندما يتم إنشاء this.say ، فإنها (مثل كل وظيفة) تحصل على مرجع داخلي. [[النطاق]] إلى البيئة المعجمية الحالية. لذلك ، تظل البيئة المعجمية لتنفيذ المستخدم الحالي في الذاكرة. جميع متغيرات المستخدم هي أيضًا خصائصه ، لذلك يتم الاحتفاظ بها بعناية ، وليست مهملة كما هو معتاد. بيت القصيد هو التأكد من أنه إذا أرادت الوظيفة الداخلية الوصول إلى متغير خارجي في المستقبل ، فإنها قادرة على القيام بذلك. كي تختصر: تحتفظ الوظيفة الداخلية بإشارة إلى الخارج معجمي البيئة. قد تصل الوظيفة الداخلية إلى المتغيرات منها في أي وقت حتى لو انتهت الوظيفة الخارجية. يحتفظ المتصفح بالبيئة المعجمية وجميع خصائصها (المتغيرات) في الذاكرة حتى تكون هناك وظيفة داخلية تشير إليها. هذا يسمى الإغلاق. | يمكن لوظائف JavaScript الوصول إلى: الحجج السكان المحليون (أي المتغيرات المحلية والوظائف المحلية) البيئة والتي تشمل: جلوبالس ، بما في ذلك DOM أي شيء في الدوال الخارجية إذا وصلت إحدى الوظائف إلى بيئتها ، فستكون الوظيفة عبارة عن إغلاق. لاحظ أن الوظائف الخارجية ليست مطلوبة ، على الرغم من أنها تقدم مزايا لا أناقشها هنا. من خلال الوصول إلى البيانات في بيئتها ، يُبقي الإغلاق تلك البيانات حية. في حالة الأحرف الفرعية للوظائف الخارجية / الداخلية ، يمكن للدالة الخارجية إنشاء بيانات محلية والخروج في النهاية ، ومع ذلك ، إن وجدت داخليةتبقى الوظيفة (الوظائف) على قيد الحياة بعد خروج الوظيفة الخارجية ، ثم تحافظ الوظيفة (الوظائف) الداخلية على البيانات المحلية للوظيفة الخارجية حية. مثال على إغلاق يستخدم البيئة العالمية: تخيل أن حدثَي Stack Overflow Vote-Up و Vote-Down يتم تنفيذهما على أنهما عمليات إغلاق ، و voiceUp_click و voiceDown_click ، والتي لها حق الوصول إلى المتغيرات الخارجية isVotedUp و isVotedDown ، والتي يتم تحديدها عالميًا. (من أجل البساطة ، أشير إلى أزرار تصويت الأسئلة في StackOverflow ، وليس مجموعة أزرار تصويت الإجابة.) عندما ينقر المستخدم على زر VoteUp ، تتحقق وظيفة التصويتUp_click ما إذا كانت VotedDown == true لتحديد ما إذا كان سيتم التصويت لصالحه أم مجرد إلغاء تصويت سلبي. وظيفة التصويتUp_click هي إغلاق لأنها تصل إلى بيئتها. var isVotedUp = خطأ ، var isVotedDown = false ؛ وظيفة التصويتUp_click () { إذا (isVotedUp) إرجاع؛ وإلا إذا (isVotedDown) SetDownVote (خطأ) ؛ آخر SetUpVote (صحيح) ؛ } وظيفة التصويت Down_click () { إذا (تم التصويت لأسفل) إرجاع؛ وإلا إذا (isVotedUp) SetUpVote (خطأ) ؛ آخر SetDownVote (صحيح) ؛ } وظيفة SetUpVote (الحالة) { isVotedUp = الحالة ؛ // قم ببعض عناصر CSS لزر التصويت } وظيفة SetDownVote (الحالة) { isVotedDown = الحالة ؛ // قم ببعض عناصر CSS لزر التصويت لأسفل } كل هذه الوظائف الأربعة مغلقة لأنها تصل جميعها إلى بيئتها. | بصفتي أبًا لطفل يبلغ من العمر 6 سنوات ، يقوم حاليًا بتدريس الأطفال الصغار (ومبتدئ نسبيًا في الترميز بدون تعليم رسمي ، لذلك ستكون هناك حاجة إلى تصحيحات) ، أعتقد أن الدرس سيكون أفضل من خلال اللعب العملي. إذا كان الطفل البالغ من العمر 6 سنوات مستعدًا لفهم معنى الإغلاق ، فعندئذٍ يكون عمره ما يكفي ليقوم بنفسه. أقترح لصق الكود في jsfiddle.net ، مع شرحه قليلاً ، وتركهم بمفردهم لتلفيق أغنية فريدة. ربما يكون النص التوضيحي أدناه أكثر ملاءمة لطفل عمره 10 سنوات. وظيفة تغني (شخص) { var firstPart = "كان هناك" + شخص + "ابتلع" ؛ var fly = function () { var مخلوق = "ذبابة" ؛ نتيجة var = "ربما تموت" ؛ تنبيه (أول جزء + مخلوق + "\ n" + نتيجة) ؛ } ؛ var spider = function () { var مخلوق = "عنكبوت" ؛ نتيجة var = "التي تهتز وتهتز وتدغدغ بداخلها" ؛ تنبيه (أول جزء + مخلوق + "\ n" + نتيجة) ؛ } ؛ var bird = function () { مخلوق فار = "طائر" ؛ نتيجة var = "كم هو سخيف!" ؛ تنبيه (أول جزء + مخلوق + "\ n" + نتيجة) ؛ } ؛ var cat = function () { var مخلوق = "قطة" ؛ var نتيجة = "تخيل ذلك!" ؛ تنبيه (أول جزء + مخلوق + "\ n" + نتيجة) ؛ } ؛ يطير()؛ العنكبوت () ؛ طائر()؛ قط()؛ } var person = "سيدة عجوز" ؛ يغني (شخص) ؛ تعليمات البيانات: البيانات عبارة عن مجموعة من الحقائق. يمكن أن تكون أرقامًا أو كلمات أو قياسات أو ملاحظات أو حتى مجرد وصف للأشياء. لا يمكنك لمسها أو شمها أو تذوقها. يمكنك كتابتها والتحدث بها وسماعها. يمكنك استخدامه لخلق طعم ورائحة اللمس باستخدام الكمبيوتر. يمكن جعله مفيدًا بواسطة الكمبيوتر باستخدام التعليمات البرمجية. الكود: كل ما ورد أعلاه يسمى كود. إنه مكتوب بلغة JavaScript. JAVASCRIPT: JavaScript هي لغة. مثل اللغة الإنجليزية أو الفرنسية أو الصينية هي لغات. هناك الكثير من اللغات التي تفهمها أجهزة الكمبيوتر والمعالجات الإلكترونية الأخرى. لكي يفهم الكمبيوتر جافا سكريبت ، فإنه يحتاج إلى مترجم. تخيل لو جاء مدرس يتحدث الروسية فقط ليعلم فصلك في المدرسة. عندما يقول المعلم "все садятся" ، لن يفهم الفصل. لكن لحسن الحظ لديك تلميذ روسي في صفك يقول للجميع أن هذا يعني "الجميع يجلسون" - هكذا تفعلون جميعًا. الفصل يشبه الكمبيوتر والتلميذ الروسي هو المترجم. بالنسبة إلى JavaScript ، يُطلق على المترجم الأكثر شيوعًا اسم المستعرض. المستعرض: عند الاتصال بالإنترنت على جهاز كمبيوتر أو جهاز لوحي أو هاتف لزيارة موقع ويب ، فإنك تستخدم متصفحًا. الأمثلة التي قد تعرفها هي Internet Explorer و Chrome و Firefox و Safari. يمكن للمتصفح فهم JavaScript وإخبار الكمبيوتر بما يجب عليه القيام به. تعليمات JavaScript تسمى وظائف. الوظيفة: وظيفة في JavaScript تشبه المصنع. قد يكون مصنعًا صغيرًا به آلة واحدة فقط بداخله. أو قد يحتوي على العديد من المصانع الصغيرة الأخرى ، لكل منها العديد من الآلات التي تؤدي وظائف مختلفة. في مصنع ملابس حقيقي ، قد يكون لديك رزم من القماش وبكرات من الخيوط تدخل وتخرج القمصان والجينز. يقوم مصنع JavaScript الخاص بنا بمعالجة البيانات فقط ، ولا يمكنه خياطة أو حفر حفرة أو إذابة المعدن. في مصنع JavaScript الخاص بنا ، يتم إدخال البيانات وإخراج البيانات. كل هذه البيانات تبدو مملة بعض الشيء ، لكنها رائعة حقًا ؛ قد يكون لدينا وظيفة تخبر الروبوت بما يجب أن يصنعه لتناول العشاء. لنفترض أنني أدعوك أنت وصديقك إلى منزلي. أنت تحب أرجل الدجاج أكثر ، وأنا أحب النقانق ، وصديقك دائمًا يريد ما تريد وصديقي لا يأكل اللحوم ليس لدي وقت للذهاب للتسوق ، لذا تحتاج الوظيفة إلى معرفة ما لدينا في الثلاجة لاتخاذ القرارات. كل مكون له وقت طهي مختلف ونريد أن يكون كل شيءيتم تقديمها ساخنة من قبل الروبوت في نفس الوقت. نحتاج إلى تزويد الوظيفة بالبيانات حول ما نحب ، يمكن للوظيفة "التحدث" إلى الثلاجة ، ويمكن للوظيفة التحكم في الروبوت. عادة ما يكون للوظيفة اسم وأقواس وأقواس. مثله: وظيفة cookMeal () {/ * أشياء داخل الوظيفة * /} لاحظ أن /*...*/ و // إيقاف الكود الذي يقرأه المتصفح. NAME: يمكنك استدعاء وظيفة أي كلمة تريدها. يعتبر مثال "cookMeal" نموذجيًا في ضم كلمتين معًا وإعطاء الثانية حرفًا كبيرًا في البداية - لكن هذا ليس ضروريًا. لا يمكن أن تحتوي على مسافة فيه ، ولا يمكن أن يكون رقمًا بمفرده. الأقواس: "الأقواس" أو () هي صندوق الرسائل الموجود على باب مصنع وظيفة JavaScript أو صندوق البريد في الشارع لإرسال حزم المعلومات إلى المصنع. في بعض الأحيان ، قد يتم وضع علامة على صندوق البريد على سبيل المثال cookMeal (أنت ، أنا ، صديقك ، صديقي ، الثلاجة ، وقت العشاء) ، وفي هذه الحالة تعرف ما هي البيانات التي يجب عليك تقديمها. الحمالات: "الأقواس" التي تبدو مثل هذه {} هي النوافذ الملونة لمصنعنا. من داخل المصنع يمكنك رؤية الخارج ، لكن من الخارج لا يمكنك الرؤية في الداخل. مثال الرمز الطويل أعلاه يبدأ الكود الخاص بنا بوظيفة الكلمة ، لذلك نعلم أنها واحدة! ثم يغني اسم الوظيفة - هذا هو وصفي الخاص لما تدور حوله الوظيفة. ثم أقواس (). توجد الأقواس دائمًا للدالة. في بعض الأحيان تكون فارغة ، وأحيانًا يكون لديهم شيء ما. هذا واحد لديه كلمة في: (شخص). بعد هذا هناك قوس مثل هذا {. هذا يمثل بداية وظيفة الغناء (). لها شريك يمثل نهاية الغناء () مثل هذا} وظيفة تغني (شخص) {/ * أشياء داخل الوظيفة * /} لذلك قد يكون لهذه الوظيفة علاقة بالغناء ، وقد تحتاج إلى بعض البيانات عن شخص ما. يحتوي على تعليمات بالداخل لفعل شيء بهذه البيانات. الآن ، بعد وظيفة sing () ، يوجد السطر بالقرب من نهاية الكود var person = "سيدة عجوز" ؛ متغير: الأحرف var تعني "متغير". المتغير مثل المغلف. في الخارج ، تم وضع علامة "شخص" على هذا الظرف. من الداخل تحتوي على قصاصة من الورق تحتوي على المعلومات التي تحتاجها وظيفتنا ، وبعض الأحرف والمسافات مرتبطة ببعضها البعض مثل قطعة من الخيط (تسمى سلسلة) تجعل عبارة تقرأ "سيدة عجوز". يمكن أن يحتوي مغلفنا على أنواع أخرى من الأشياء مثل الأرقام (تسمى الأعداد الصحيحة) ، والتعليمات (تسمى الوظائف) ، والقوائم (تسمى المصفوفات). لأن هذا المتغير مكتوب خارج كل الأقواس {} ، ولأنك تستطيع أن ترى من خلال النوافذ الملونة عندما تكون داخل الأقواس ، يمكن رؤية هذا المتغير من أي مكان في الكود. نسمي هذا "المتغير الشامل". المتغير العالمي: الشخص هو متغير عالمي ، وهذا يعني أنه إذا قمت بتغيير قيمته من "سيدة عجوز" إلى "شاب" ، فسيظل الشخص شابًا حتى تقرر تغييره مرة أخرى وأن أي وظيفة أخرى في يمكن للقانون أن يرى أنه شاب. اضغط على الزر F12 أو انظر إلى إعدادات الخيارات لفتح وحدة تحكم مطور المتصفح واكتب "شخص" لترى ما هي هذه القيمة. اكتب شخص = "شاب" لتغييره ثم اكتب "شخص" مرة أخرى لترى أنه قد تم تغييره. بعد هذا لدينا الخط يغني (شخص) ؛ هذا الخط يستدعي الوظيفة ، كما لو كان يستدعي كلبًا "تعال وغني ، تعال واحصل على شخص!" عندما يقوم المتصفح بتحميل كود JavaScript عند وصوله إلى هذا السطر ، فإنه سيبدأ الوظيفة. أضع السطر في النهاية للتأكد من أن المتصفح يحتوي على جميع المعلومات التي يحتاجها لتشغيله. تحدد الوظائف الإجراءات - الوظيفة الرئيسية تتعلق بالغناء. يحتوي على متغير يسمى الجزء الأول وينطبق على الغناء عن الشخص الذي ينطبق على كل آية من آيات الأغنية: "كان هناك" + شخص + "ابتلع". إذا قمت بكتابة firstPart في وحدة التحكم ، فلن تحصل على إجابة لأن المتغير مغلق في وظيفة - لا يستطيع المتصفح رؤية داخل النوافذ الملونة للأقواس. الإغلاق: عمليات الإغلاق هي الوظائف الأصغر الموجودة داخل وظيفة Sing () الكبيرة. المصانع الصغيرة داخل المصنع الكبير. كل منهم لديه أقواس خاصة به مما يعني أن المتغيرات الموجودة بداخلهم لا يمكن رؤيتها من الخارج. هذا هو السبب في أن أسماء المتغيرات (المخلوق والنتيجة) يمكن أن تتكرر في الإغلاق ولكن بقيم مختلفة. إذا قمت بكتابة أسماء المتغيرات هذه في نافذة وحدة التحكم ، فلن تحصل على قيمتها لأنها مخفية بطبقتين من النوافذ الملونة. تعرف جميع عمليات الإغلاق ما هو متغير الدالة sing () المسمى firstPart ، لأنه يمكنهم الرؤية من نوافذهم الملونة. بعد الإغلاق تأتي الخطوط يطير()؛ العنكبوت () ؛ طائر()؛ قط()؛ ستستدعي وظيفة sing () كل من هذه الوظائف بالترتيب المعطى لها. ثم يتم عمل وظيفة sing (). | حسنًا ، بالتحدث مع طفل يبلغ من العمر 6 سنوات ، ربما أستخدم الجمعيات التالية. تخيل - أنت تلعب معالإخوة والأخوات الصغار في المنزل بأكمله ، وأنت تتنقل بألعابك وتحضر بعضًا منهم إلى غرفة أخيك الأكبر. بعد فترة عاد أخوك من المدرسة وذهب إلى غرفته ، وأغلق بداخلها ، لذا لم يعد بإمكانك الوصول إلى الألعاب التي تركت هناك بطريقة مباشرة. لكن يمكنك أن تطرق الباب وتطلب من أخيك تلك الألعاب. وهذا ما يسمى بإغلاق اللعبة ؛ أخوك اختلقها من أجلك ، وهو الآن في النطاق الخارجي. قارن مع الموقف الذي كان فيه الباب مغلقًا بمسودة هواء ولا يوجد أحد بالداخل (تنفيذ الوظيفة العامة) ، ثم تحدث بعض حرائق محلية وتحرق الغرفة (مجمع القمامة: D) ، ثم تم بناء غرفة جديدة والآن يمكنك المغادرة ألعاب أخرى هناك (مثيل وظيفي جديد) ، لكن لا تحصل أبدًا على نفس الألعاب التي تُركت في حالة الغرفة الأولى. بالنسبة للطفل المتقدم ، أود أن أضع شيئًا مثل ما يلي. إنه ليس مثاليًا ، لكنه يجعلك تشعر بما هو عليه: وظيفة playInBrothersRoom (withToys) { // نغلق الألعاب التي لعبناها في غرفة الأخ. عندما يعود ويقفل الباب // من المفترض أن يكون أخوك في كائن [[النطاق]] الخارجي الآن. الحمد لله يمكنك التواصل معه. var closeToys = withToys || [] ، returnToy ، countIt ، لعبة ؛ // مجرد مساعد إغلاق آخر ، للاستخدام الداخلي للأخ. var brotherGivesToyBack = الوظيفة (لعبة) { // طلب جديد. لا يوجد إغلاق حتى الآن على يد الأخ. امنحه وقتا. returnToy = خالية ؛ إذا (toy && closToys.length> 0) {// إذا طلبنا لعبة معينة ، فإن الأخ سيبحث عنها. لـ (countIt = closToys.length؛ countIt؛ countIt--) { إذا (closeToys [countIt - 1] == لعبة) { returnToy = 'خذ' + closToys.splice (countIt - 1، 1) + '، little boy!'؛ استراحة؛ } } returnToy = returnToy || "مرحبًا ، لم أجد أي" + لعبة + "هنا. ابحث عنها في غرفة أخرى. '؛ } else if (closToys.length> 0) {// وإلا ، ما عليك سوى إعادة كل ما لديه في الغرفة. returnToy = 'ها! '+ closeToys.join ('، ') +'. '؛ closeToys = [] ، } آخر { returnToy = 'مرحبًا ، يا روبيان ، لقد أعطيتك كل شيء!' ؛ } console.log (returnToy) ؛ } عودة الأخ } // أنت تلعب في المنزل ، بما في ذلك غرفة الأخ. var toys = ['teddybear'، 'car'، 'jumpingrope']، askBrotherForClosuredToy = playInBrothersRoom (اللعب) ؛ // الباب مغلق ، والأخ جاء من المدرسة. لا يمكنك الغش وإخراجها مباشرة. console.log (askBrotherForClosuredToy.closureToys) ، // غير معرف // لكن يمكنك أن تطلب من أخيك بأدب أن يردها. askBrotherForClosuredToy ("teddybear") ؛ // الصيحة ، ها هو ، تيدي بير askBrotherForClosuredToy ("كرة") ؛ // لن يتمكن الأخ من العثور عليه. askBrotherForClosuredToy () ، // يمنحك الأخ كل الباقي askBrotherForClosuredToy () ، // لم يتبق شيء هناك كما ترون ، الألعاب المتبقية في الغرفة يمكن الوصول إليها عبر الأخ وبغض النظر عما إذا كانت الغرفة مقفلة. هنا هو jsbin للتلاعب به. | إجابة لطفل يبلغ من العمر ست سنوات (بافتراض أنه يعرف ما هي الوظيفة وما هو المتغير وما هي البيانات): يمكن للوظائف إرجاع البيانات. نوع واحد من البيانات التي يمكنك إرجاعها من دالة هو وظيفة أخرى. عند إرجاع هذه الوظيفة الجديدة ، لا تختفي جميع المتغيرات والوسيطات المستخدمة في الوظيفة التي أنشأتها. وبدلاً من ذلك ، فإن هذه الوظيفة الأم "تُغلق". بمعنى آخر ، لا شيء يمكن أن ينظر بداخله ويرى المتغيرات التي استخدمها باستثناء الوظيفة التي أعادها. تتمتع هذه الوظيفة الجديدة بقدرة خاصة على النظر إلى الوراء داخل الوظيفة التي أنشأتها ورؤية البيانات الموجودة بداخلها. وظيفة the_closure () { فار س = 4 ؛ وظيفة الإرجاع () { عودة س ؛ // هنا ، ننظر إلى الوراء داخل the_closure لمعرفة قيمة x } } var myFn = the_closure () ، myFn () ، // => 4 هناك طريقة أخرى بسيطة حقًا لشرحها وهي من حيث النطاق: في أي وقت تنشئ فيه نطاقًا أصغر داخل نطاق أكبر ، سيتمكن النطاق الأصغر دائمًا من رؤية ما هو موجود في النطاق الأكبر. | الوظيفة في JavaScript ليست مجرد إشارة إلى مجموعة من التعليمات (كما في لغة C) ، ولكنها تتضمن أيضًا بنية بيانات مخفية تتكون من مراجع لجميع المتغيرات غير المحلية التي تستخدمها (المتغيرات الملتقطة). تسمى هذه الوظائف المكونة من قطعتين عمليات الإغلاق. يمكن اعتبار كل وظيفة في JavaScript بمثابة إغلاق. عمليات الإغلاق هي وظائف مع الدولة. إنه مشابه إلى حد ما لـ "هذا" بمعنى أن "هذا" يوفر أيضًا حالة لوظيفة ولكن وظيفة و "هذا" كائنات منفصلة ("هذا" مجرد معلمة رائعة ، والطريقة الوحيدة لربطها بشكل دائم الوظيفة هي إنشاء إغلاق). بينما تعيش "هذه" والوظيفة دائمًا بشكل منفصل ، لا يمكن فصل الوظيفة عن إغلاقها ولا توفر اللغة أي وسيلة للوصول إلى المتغيرات الملتقطة. لأن كل هذه المتغيرات الخارجية المشار إليها بواسطة دالة متداخلة معجميًا هي في الواقع متغيرات محلية في سلسلة التضمين المعجمي لهاالدوال (يمكن افتراض أن المتغيرات العامة هي متغيرات محلية لبعض وظائف الجذر) ، وكل تنفيذ منفرد لوظيفة ما يُنشئ مثيلات جديدة لمتغيراتها المحلية ، ويترتب على ذلك أن كل تنفيذ لدالة يعود (أو نقلها بطريقة أخرى ، مثل تسجيله على أنه رد نداء) وظيفة متداخلة تخلق إغلاقًا جديدًا (مع مجموعتها الفريدة المحتملة من المتغيرات غير المحلية المشار إليها والتي تمثل سياق التنفيذ الخاص بها). أيضًا ، يجب أن يكون مفهومًا أن المتغيرات المحلية في JavaScript لا يتم إنشاؤها على إطار المكدس ، ولكن على الكومة ويتم إتلافها فقط عندما لا يقوم أحد بالإشارة إليها. عند إرجاع دالة ، يتم تقليل الإشارات إلى متغيراتها المحلية ، ولكن لا يزال من الممكن أن تظل غير خالية إذا أصبحت أثناء التنفيذ الحالي جزءًا من الإغلاق ولا يزال يتم الرجوع إليها من خلال وظائفها المتداخلة معجمًا (والذي يمكن أن يحدث فقط إذا كانت المراجع إلى تم إرجاع هذه الوظائف المتداخلة أو نقلها بطريقة أخرى إلى بعض التعليمات البرمجية الخارجية). مثال: function foo (initValue) { // لا يتم إتلاف هذا المتغير عند إنهاء وظيفة foo. // يتم التقاطها بواسطة الوظيفتين المتداخلتين اللتين تم إرجاعهما أدناه. var value = initValue ؛ // لاحظ أنه تم إنشاء الوظيفتين المرتجعتين الآن. // إذا تم استدعاء وظيفة foo مرة أخرى ، فستعود // دوال جديدة تشير إلى متغير "قيمة" مختلف. إرجاع { getValue: function () {قيمة الإرجاع؛ } ، setValue: الوظيفة (newValue) {القيمة = newValue ؛ } } } شريط الوظائف () { // foo يعين "قيمة" المتغير المحلي الخاص به على 5 ويعيد كائنًا به // لا تزال وظيفتان تشيران إلى هذا المتغير المحلي var obj = foo (5) ؛ // استخراج الوظائف فقط لإظهار أنه لا يوجد "هذا" متضمن هنا var getValue = obj.getValue ؛ var setValue = obj.setValue ؛ تنبيه (getValue ()) ؛ // يعرض 5 setValue (10) ؛ تنبيه (getValue ()) ؛ // يعرض 10 // في هذه المرحلة يتم إتلاف وظائف getValue و setValue // (في الواقع يتم تدميرها عند التكرار التالي لمجمع القمامة). // لم يعد المتغير المحلي "value" في foo يُشار إليه بواسطة // أي شيء ودمر أيضًا. } شريط()؛ | ربما يتجاوز ذلك بقليل كل الأطفال الذين يبلغون من العمر ست سنوات ، ولكن بعض الأمثلة التي ساعدت في جعل مفهوم الإغلاق في JavaScript انقر بالنسبة لي. الإغلاق هو وظيفة لها حق الوصول إلى نطاق وظيفة أخرى (متغيراتها ووظائفها). أسهل طريقة لإنشاء إغلاق هي باستخدام وظيفة داخل دالة ؛ والسبب هو أنه في جافا سكريبت ، تتمتع الوظيفة دائمًا بإمكانية الوصول إلى نطاق الوظيفة التي تحتوي عليها. دالة خارجية () { var OuterVar = "قرد" ؛ الوظيفة innerFunction () { تنبيه (الجزء الخارجي) ؛ } الوظيفة الداخلية () ؛ } الوظيفة الخارجية () ؛ تنبيه: قرد في المثال أعلاه ، يتم استدعاء الوظيفة الخارجية والتي بدورها تستدعي الوظيفة الداخلية. لاحظ كيف يتوفر ExternalVar للدالة الداخلية ، ويتضح ذلك من خلال التنبيه الصحيح لقيمة ExternalVar. الآن ضع في اعتبارك ما يلي: دالة خارجية () { var OuterVar = "قرد" ؛ الوظيفة innerFunction () { العودة الخارجي } عودة الوظيفة الداخلية ؛ } var referenceToInnerFunction = العوامل الخارجية () ، تنبيه (referenceToInnerFunction ()) ؛ تنبيه: قرد يتم تعيين ReferenceToInnerFunction إلى العوامل الخارجية () ، والتي تُرجع ببساطة مرجعًا إلى الوظيفة الداخلية. عندما يتم استدعاء referenceToInnerFunction ، فإنه يُرجع OuterVar. مرة أخرى ، كما ورد أعلاه ، يوضح هذا أن الدالّة الداخلية لها حق الوصول إلى الجزء الخارجي ، وهو متغير للدالة الخارجية. علاوة على ذلك ، من المثير للاهتمام ملاحظة أنه يحتفظ بهذا الوصول حتى بعد انتهاء وظيفة ExternalFunction من التنفيذ. وهنا حيث تصبح الأشياء ممتعة حقًا. إذا أردنا التخلص من الدالة الخارجية ، فلنقل تعيينها على قيمة خالية ، فقد تعتقد أن دالة ReferenceToInnerFunction ستفقد وصولها إلى قيمة OuterVar. ولكن هذا ليس هو الحال. دالة خارجية () { var OuterVar = "قرد" ؛ الوظيفة innerFunction () { العودة الخارجي } عودة الوظيفة الداخلية ؛ } var referenceToInnerFunction = العوامل الخارجية () ، تنبيه (referenceToInnerFunction ()) ؛ دالة خارجية = خالية ؛ تنبيه (referenceToInnerFunction ()) ؛ تنبيه: قرد تنبيه: قرد لكن كيف هذا؟ كيف يمكن أن لا تزال دالة referenceToInnerFar في معرفة قيمة OuterVar الآن بعد أن تم ضبط الوظيفة الخارجية على قيمة خالية؟ يرجع السبب في استمرار إمكانية الوصول إلى دالة referenceToInner إلى قيمة OuterVar لأنه عندما تم إنشاء الإغلاق لأول مرة عن طريق وضع دالة داخلية داخل دالة خارجية ، أضافت الوظيفة الداخلية مرجعًا إلى نطاق الوظيفة الخارجية (متغيراتها ووظائفها) إلى سلسلة نطاقها. ما يعنيه هذا هو أن الوظيفة الداخلية لها مؤشر أو مرجع لجميع متغيرات الوظيفة الخارجية ، بما في ذلك الجزء الخارجي. لذلك ، حتى عندما تنتهي الدالة الخارجية من التنفيذ ، أو حتى إذا تم حذفها أو ضبطها على قيمة خالية ، فإن المتغيرات الموجودة في نطاقها ، مثل الجزء الخارجي ، تظل في الذاكرة بسبب المرجع المعلق لها من جانب الوظيفة الداخلية التي تم إرجاعها إلى مرجع إلى وظيفة داخلية. للإفراج عن العناصر الخارجية وبقية متغيرات الوظيفة الخارجية منالذاكرة ، يجب عليك التخلص من هذه الإشارة البارزة إليها ، على سبيل المثال من خلال تعيين وظيفة referenceToInner على قيمة خالية أيضًا. ////////// شيئين آخرين حول الإغلاق يجب ملاحظته. أولاً ، سيكون للإغلاق دائمًا إمكانية الوصول إلى القيم الأخيرة لوظيفته المحتوية. دالة خارجية () { var OuterVar = "قرد" ؛ الوظيفة innerFunction () { تنبيه (الجزء الخارجي) ؛ } OuterVar = "غوريلا" ؛ الوظيفة الداخلية () ؛ } الوظيفة الخارجية () ؛ تنبيه: غوريلا ثانيًا ، عندما يتم إنشاء إغلاق ، فإنه يحتفظ بمرجع لجميع متغيرات ووظائف وظيفة التضمين الخاصة به ؛ ليس من حقها أن تنتقي وتختار. ومع ذلك ، يجب استخدام الإغلاق بشكل مقتصد ، أو على الأقل بعناية ، حيث يمكن أن يكون مكثفًا للذاكرة ؛ يمكن الاحتفاظ بالكثير من المتغيرات في الذاكرة لفترة طويلة بعد انتهاء تنفيذ الوظيفة المحتوية. | سأوجههم ببساطة إلى صفحة إغلاق Mozilla. إنه التفسير الأفضل والأكثر إيجازًا وبساطة لأساسيات الإغلاق والاستخدام العملي الذي وجدته. يوصى بشدة لأي شخص يتعلم JavaScript. ونعم ، أوصي به حتى لطفل يبلغ من العمر 6 سنوات - إذا كان الطفل البالغ من العمر 6 سنوات يتعلم عن الإغلاق ، فمن المنطقي أن يكونوا جاهزين لفهم الشرح الموجز والبسيط المقدم في المقالة. | 1 2 3 التالى ليس الجواب الذي تبحث عنه؟ تصفح الأسئلة الأخرى الموسومة بوظيفة جافا سكريبت متغيرات إغلاق النطاق أو اطرح سؤالك الخاص.